#ifndef AGTK_SHADER_H
#define AGTK_SHADER_H

namespace agtk {

struct UniformShaderParameter
{
	UniformShaderParameter(GLint glHandle) {
		m_glHandle = glHandle;
	}

	void SetBool(bool v) {
		if (v)
			glUniform1i(m_glHandle, 1);
		else
			glUniform1i(m_glHandle, 0);
	}
	void Set1f(float x) {
		glUniform1f(m_glHandle, x);
	}
	void Set2f(float x, float y) {
		glUniform2f(m_glHandle, x, y);
	}
	void Set3f(float x, float y, float z) {
		glUniform3f(m_glHandle, x, y, z);
	}
	void Set4f(float x, float y, float z, float w) {
		glUniform4f(m_glHandle, x, y, z, w);
	}
	void Set1i(int x) {
		glUniform1i(m_glHandle, x);
	}
	void Set2i(int x, int y) {
		glUniform2i(m_glHandle, x, y);
	}
	void Set3i(int x, int y, int z) {
		glUniform3i(m_glHandle, x, y, z);
	}
	void Set4i(int x, int y, int z, int w) {
		glUniform4i(m_glHandle, x, y, z, w);
	}

private:
	GLint m_glHandle;
};

struct ShaderAttribute
{
	ShaderAttribute(GLint glHandle) {
		m_glHandle = glHandle;
	}

	void Set1f(float x) {
		glVertexAttrib1f(m_glHandle, x);
	}
	void Set2f(float x, float y) {
		glVertexAttrib2f(m_glHandle, x, y);
	}
	void Set3f(float x, float y, float z) {
		glVertexAttrib3f(m_glHandle, x, y, z);
	}
	void Set4f(float x, float y, float z, float w) {
		glVertexAttrib4f(m_glHandle, x, y, z, w);
	}

private:
	GLint m_glHandle;
};

class Shader
{
public:
	/** Constructor. **/
	Shader(char* vertFile, char* fragFile);

	/** Destructor. **/
	~Shader(void);

	/** Enable the current shader for use or disable the currently active one.
		@param use Use this shader. If false, unload the active shader program and use the fixed-function pipeline.
	**/
	void UseShader(bool use = true);

	/** Get a handle for a uniform parameter in the shader.
		@param name The name of the uniform.
	**/
	UniformShaderParameter* GetUniform(const char* name);

	/** Get a handle for an attribute in the shader.
		@param name The name of the attribute.
	**/
	ShaderAttribute* GetAttribute(const char* name);

private:
	GLuint m_vertexShader;
	GLuint m_fragmentShader;
	GLuint m_shaderProgram;

public:
	// Per-frame
	UniformShaderParameter* agtk_eyePosition;
	UniformShaderParameter* agtk_ambientColor;

	// Per-model
	UniformShaderParameter* agtk_diffuseColor;
	UniformShaderParameter* agtk_falloffColor;
	UniformShaderParameter* agtk_specularIntensity;
	UniformShaderParameter* agtk_specularPower;
	UniformShaderParameter* agtk_glowIntensity;
	UniformShaderParameter* agtk_falloffIntensity;
	UniformShaderParameter* agtk_falloffPower;
	UniformShaderParameter* agtk_falloffDetail;
	UniformShaderParameter* agtk_diffuseMap;
	UniformShaderParameter* agtk_normalMap;
	UniformShaderParameter* agtk_specularMap;
	UniformShaderParameter* agtk_glowMap;
	UniformShaderParameter* agtk_useDiffuseMap;
	UniformShaderParameter* agtk_useNormalMap;
	UniformShaderParameter* agtk_useSpecularMap;
	UniformShaderParameter* agtk_useGlowMap;

	// Per-vertex
	ShaderAttribute* agtk_tangent;
	ShaderAttribute* agtk_bitangent;
};

}

#endif